/** Definition of the Parser class.
 * @file 
 * @author Jeremy Schultz
 */

#ifndef	__PARSER_H_
#define	__PARSER_H_

#include <iostream>
#include "Administration.h"
#include "Scanner.h"
#include "Token.h"
#include "First.h"
#include "Follow.h"
#include "PLset.h"

using namespace std;


#define MAX_LABELS  500

/** The  Parser for the PL language.
 */
class Parser	{
	private:
		Administration* admin;			/**< Administration, error handler */
		Scanner* scanner;				/**< Scanner, next Token & Line Number */
		SymbolTable* symTable;			/**< Symbol Table */
		First* first;					/**< First set */
		Follow* follow;					/**< Follow set */

		Token *curToken;				/**< The Current Token */	
		string indent;					/**< Indent output with content */
		string tabStop;					/**< The tab stop to use for indenting */

		//---------------------------------------------------------------------
		// Utility Functions


		/** Create a new Label.
		 * @return A new Label
		 */
		int newLabel();

		//---------------------------------------------------------------------
		// Match Functions
		
		/** Match terminal (Word).
		 * @param terminal	The word to match
		 * @param syncSet	The set to sync to when an error occurs
		 */
		void Parser::match(Word* terminal, PLset* syncSet); 

		/** Match terminal (Token).
		 * @param termType	The terminal type to match
		 * @param syncSet	The set to sync to when an error occurs
		 */
		void Parser::match(Token::TokenType termType, PLset* syncSet);

		/** Match an ID.
		 * @return The word 
		 * @param syncSet	The set to sync to when an error occurs
		 */
		void Parser::matchID(Word* w, PLset* syncSet);



		//---------------------------------------------------------------------
		// Non-terminal Functions
		
		/** Non-terminal program.
		 * @param syncSet	The syncSet to be used for error recovery
		 */
		void Parser::program(PLset* syncSet);

		/** Non-terminal block.
		 * @param lVarLength  The varlength Label
		 * @param lAddress    The address label
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::block(int lVarLength, int lAddress, PLset* syncSet);

		/** Non-terminal definitionPart.
		 * @param varLength  The variable Length 
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::definitionPart(int &varLength, PLset* syncSet);

		/** Non-terminal definition.
		 * @param varLength  The variable Length 
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::definition(int &varLength, PLset* syncSet);

		/** Non-terminal constantDefinition.
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::constantDefinition(PLset* syncSet);

		/** Non-terminal variableDefinition.
		 * @param varLength  The variable Length 
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::variableDefinition(int &varLength, PLset* syncSet);

		/** Non-terminal variableDefinition1.
		 * @param varLength  The variable Length 
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::variableDefinition1(Word* wtype, int &varLength, PLset* syncSet);

		/** Non-terminal typeSymbol.
		 * @param w         Set the type found in w
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::typeSymbol(Word* w, PLset* syncSet);

		/** Non-terminal variableList.
		 * @param wList     A list of variables
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::variableList(vector<Word*> &wList, PLset* syncSet);

		/** Non-terminal variableName1.
		 * @param wList     A list of variables
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::variableName1(vector<Word*> &wList, PLset* syncSet);

		/** Non-terminal procedureDefinition.
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::procedureDefinition(PLset* syncSet);

		/** Non-terminal statementPart.
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::statementPart(PLset* syncSet);

		/** Non-terminal statement.
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::statement(PLset* syncSet);

		/** Non-terminal emptyStatement.
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::emptyStatement(PLset* syncSet);

		/** Non-terminal readStatement.
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::readStatement(PLset* syncSet);

		/** Non-terminal variableAccessList.
		 * @param wList     A list of variables
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::variableAccessList(vector<Word*> &wList, PLset* syncSet);

		/** Non-terminal variableAccess1.
		 * @param wList     A list of variables
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::variableAccess1(vector<Word*> &wList, PLset* syncSet);

		/** Non-terminal writeStatement.
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::writeStatement(PLset* syncSet);

		/** Non-terminal expressionList.
		 * @param dTypes	A list of Data Types
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::expressionList(vector<WordData::DataType> &dTypes, PLset* syncSet);

		/** Non-terminal expression1.
		 * @param dTypes	A list of Data Types
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::expression1(vector<WordData::DataType> &dTypes, PLset* syncSet);

		/** Non-terminal assignmentStatement.
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::assignmentStatement(PLset* syncSet);

		/** Non-terminal procedureStatement.
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::procedureStatement(PLset* syncSet);

		/** Non-terminal ifStatement.
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::ifStatement(PLset* syncSet);

		/** Non-terminal doStatement.
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::doStatement(PLset* syncSet);

		/** Non-terminal guardedCommandList.
		 * @param lGoto		The goto Label
		 * @param lNext		The next Label
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::guardedCommandList(int lGoto, int &lNext, PLset* syncSet);

		/** Non-terminal guardedCommand1.
		 * @param lGoto		The goto Label
		 * @param lNext		The next Label
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::guardedCommand1(int lGoto, int &lNext, PLset* syncSet);

		/** Non-terminal guardedCommand.
		 * @param lNext		The next Label
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::guardedCommand(int &lNext, PLset* syncSet);

		/** Non-terminal expression.
		 * @param dType 	A list of Data Types
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::expression(WordData::DataType &dType, PLset* syncSet);

		/** Non-terminal primaryExpression1.
		 * @param dType 	A list of Data Types
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::primaryExpression1(WordData::DataType &dType, PLset* syncSet);

		/** Non-terminal primaryOperator.
		 * @param oper		The operator found
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::primaryOperator(string &oper, PLset* syncSet);

		/** Non-terminal primaryExpression.
		 * @param dType 	A list of Data Types
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::primaryExpression(WordData::DataType &dtype, PLset* syncSet);

		/** Non-terminal primaryExpression11.
		 * @param dType 	A list of Data Types
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::primaryExpression11(WordData::DataType &dtype, PLset* syncSet);

		/** Non-terminal relationalOperator.
		 * @param relOp		The operator found
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::relationalOperator(string &relOp, PLset* syncSet);

		/** Non-terminal simpleExpression.
		 * @param dType 	A list of Data Types
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::simpleExpression(WordData::DataType &dtype, PLset* syncSet);

		/** Non-terminal negativeSymbol.
		 * @param neg		The negative operation found
		 * @param dType 	A list of Data Types
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::negativeSymbol(string &neg, WordData::DataType &dtype, PLset* syncSet);

		/** Non-terminal simpleExpression1.
		 * @param dType 	A list of Data Types
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::simpleExpression1(WordData::DataType &dtype, PLset* syncSet);

		/** Non-terminal addingOperator.
		 * @param oper		The operator found
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::addingOperator(string &oper, PLset* syncSet);

		/** Non-terminal term.
		 * @param dType 	A list of Data Types
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::term(WordData::DataType &dtype, PLset* syncSet);

		/** Non-terminal term1.
		 * @param dType 	A list of Data Types
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::term1(WordData::DataType &dtype, PLset* syncSet);

		/** Non-terminal multiplyingOperator.
		 * @param oper		The operator found
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::multiplyingOperator(string &oper, PLset* syncSet);

		/** Non-terminal factor.
		 * @param dType 	A list of Data Types
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::factor(WordData::DataType &dtype, PLset* syncSet);

		/** Non-terminal variableAccess.
		 * @param w			The word accessed
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::variableAccess(Word* w, PLset* syncSet);

		/** Non-terminal indexedSelector.
		 * @param w			The word 
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::indexedSelector(Word *w, PLset* syncSet);

		/** Non-terminal constant.
		 * @param w			The word 
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::constant(Word* w, PLset* syncSet);

		/** Non-terminal booleanSymbol.
		 * @param w			The word 
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::booleanSymbol(Word* w, PLset* syncSet);

		/** Non-terminal numeral.
		 * @param w			The word 
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::numeral(Word* w, PLset* syncSet);

		/** Non-terminal constantName.
		 * @param w			The word 
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::constantName(Word* w, PLset* syncSet);

		/** Non-terminal variableName.
		 * @param w			The word 
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::variableName(Word* w, PLset* syncSet);

		/** Non-terminal procedureName.
		 * @param w			The word 
		 * @param syncSet	The sync set to be used for error recovery
		 */
		void Parser::procedureName(Word* w, PLset* syncSet);


	public:		
		/** Constructor.
		 * @param _scanner	The scanner that retrieves Tokens 
		 * @param _admin	The administration class that handles errors
		 * @param _symTable	The SymbolTable class that stores Tokens 
		 */
		Parser(Scanner* _scanner, Administration* _admin, SymbolTable* _symTable);

		/** Start the Parser.
		 */
		void start();
	
		/** Sync input.
		 * Sync according to the Sync set
		 * @param syncSet	The set to sync the input to
		 */
		void Parser::sync(PLset* syncSet);

		
		/** Get Numeric Value
		 * Get the numeric value (bool or integer) from a word.
		 * Used to get the array size or return the value of a constant.
		 * If word is an constant name, then w will be modified to the 
		 *  what constant name pointed to.
		 * @param w The word to get the numeric value from
		 * @return The integer (numeric value)
		 */
		int Parser::getNumericValue(Word* w);

};
#endif
